package br.elsa.survey.domain.questions;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;

/**
 * Abstraction of Multiple Choice Question
 * 
 * @author diego
 * @since 2010-10-08
 * @param <T>
 *            Type of question options
 */
@MappedSuperclass
public abstract class MultipleChoiceQuestion<T extends Option> extends Question {

	private static final long serialVersionUID = -6921294423889840535L;

	/**
	 * Flag indicating if the question allows blank answers.
	 */
	protected boolean nullableAnswer;

	/**
	 * List with the possible options
	 */
	@OneToMany(mappedBy = "question", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	protected List<T> options = new ArrayList<T>();

	public MultipleChoiceQuestion() {

		this.setNullableAnswer(false);
	}

	/**
	 * Adds a new {@link CheckboxOption} to the {@code options} list
	 * 
	 * @param option
	 *            the new {@link CheckboxOption}
	 * @exception InvalidParameterException
	 *                In case of the {@code option} parameter is null
	 */
	public void addOption(T option) {

		if (option == null) {
			throw new InvalidParameterException("The parameter can not be null.");
		}

		options.add(option);
	}

	/**
	 * Removes a {@link CheckboxOption} from the {@code options} list
	 * 
	 * @param option
	 *            the new {@link CheckboxOption}
	 */
	public void removeOption(T option) {

		if (option != null) {
			options.remove(option);
		}
	}

	/**
	 * Removes the last {@link CheckboxOption} from the {@code options} list
	 */
	public void removeLastOption() {

		if (options.size() > 0) {
			options.remove(options.size() - 1);
		}
	}

	/**
	 * Creates a new empty {@link CheckboxOption} and add it to the
	 * {@code options} list
	 * 
	 * <p>
	 * The relation between {@link CheckboxQuestion} and {@link CheckboxOption}
	 * is composition and the responsibility of creating a new
	 * {@link CheckboxOption} belongs to the {@link CheckboxQuestion}
	 * </p>
	 */
	public abstract void createNewEmptyOption();

	/**
	 * Getter method to retrieve the {@code options} list
	 * 
	 * @return the {@code options} list
	 */
	public List<T> getOptions() {
		return options;
	}

	/**
	 * Sets the new {@code options} list
	 * 
	 * @param options
	 *            the {@code options} list
	 * @exception InvalidParameterException
	 *                In case of the {@code options} parameter is null
	 */
	public void setOptions(List<T> options) {
		if (options == null) {
			throw new InvalidParameterException("The options parameter can not be null");
		}

		this.options = options;
	}

	/**
	 * Sets the question to accept null answers ({@code true}) or not (
	 * {@code false})
	 * 
	 * @param nullableAnswer
	 *            {@code true} to accept null answers, {@code false} otherwise
	 */
	public void setNullableAnswer(boolean nullableAnswer) {
		this.nullableAnswer = nullableAnswer;
	}

	/**
	 * Asks if the question accept null answers
	 * 
	 * @return {@code true} if null answers are accepted, {@code false}
	 *         otherwise
	 */
	public boolean isNullableAnswer() {
		return nullableAnswer;
	}
}
